package demo4

import (
	"fmt"
)

/*
	接口声明格式
		type 接口类型名 interface{
			方法名1( 参数列表1 ) 返回值列表1
			方法名2( 参数列表2 ) 返回值列表2
			…
		}

	1. 接口类型名：使用 type 将接口定义为自定义的类型名。Go语言的接口在命名时，一般会在单词后面添加 er，如有写操作的接口叫 Writer
	2. 当方法名首字母是大写时，且这个接口类型名首字母也是大写时，这个方法可以被接口所在的包（package）之外的代码访问
	3. 参数列表、返回值列表：参数列表和返回值列表中的参数变量名可以被忽略，例如:
		type writer interface{
			Write([]byte) error
		}
	4. Go语言的每个接口中的方法数量不会很多。Go语言希望通过一个接口精准描述它自己的功能，
			而通过多个接口的嵌入和组合的方式将简单的接口扩展为复杂的接口

	接口的实现
	1. 实现关系在 Go语言中是隐式的。两个类型之间的实现关系不需要在代码中显式地表示出来。Go语言中没有类似于 implements 的关键字。
	2. 接口定义后，需要实现接口，调用方才能正确编译通过并使用接口。接口的实现需要遵循两条规则才能让接口可用。
		2.1 接口被实现的条件一：接口的方法与实现接口的类型方法格式一致
		2.2 接口被实现的条件二：接口中所有方法均被实现
*/

// 这个接口可以调用 Write() 方法写入一个字节数组（[]byte），返回值告知写入字节数（n int）和可能发生的错误（err error）。
type writer interface {
	Write([]byte) (n int, err error)
}

type stringer interface {
	Stirng() string
}

/* demo1 */
// 定义一个数据写入器
type dataWriter interface {
	writeData(data interface{}) error

	// 方法: 能否写入
	canWrite() bool
}

// 定义文件结构体，用于实现 dataWriter
type file struct{}

// 实现DataWriter接口的WriteData方法
func (f *file) writeData(data interface{}) error {
	// 模拟数据写入
	fmt.Println("writeData: ", data)
	return nil
}

// 实现 canWrite 方法
func (f *file) canWrite() bool {
	return true
}

// TestDemo42 接口
func TestDemo42() {
	/*
		demo1:  接口的方法与实现接口的类型方法格式一致
			1. 在类型中添加与接口签名一致的方法就可以实现该方法。签名包括方法中的名称、参数列表、返回参数列表
		常见的报错：
			1. 函数名不一致导致的报错
			2. 实现接口的方法签名不一致导致的报错
	*/
	// 实例化 file
	file1 := new(file)

	// 声明一个 dataWriter 的接口
	var writer dataWriter

	// 这算是一种实现接口
	// 将接口赋值 f, 也就是 *f 类型
	// 虽然两个变量类型不一致。但是 writer 是一个接口，且 f 已经完全实现了 DataWriter() 的所有方法，因此赋值是成功的。
	writer = file1

	// 使用 dataWriter 接口接入数据
	writer.writeData("data")

	/*
		demo2: 接口中所有方法均被实现
		  1. 当一个接口中有多个方法时，只有这些方法都被实现了，接口才能被正确编译并使用。
	*/
}
